package service

import (
	"context"
	"database/sql/driver"
	"encoding/json"
	"fmt"
	common "golang_start/common"
	"os"
	"reflect"
	"strconv"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
)

func init() {

}

//gorm.Model
/*时间结构体-固定名称*/
type CodeContentParsertime string

type CodeContent struct {
	Id int `gorm:"primaryKey" form:"id" json:"id"`

	Type_id int `gorm:"column:type_id" json:"type_id" form:"type_id"` //分类ID

	User_id int `gorm:"column:user_id" json:"user_id" form:"user_id"` //用户ID

	Code_title string `gorm:"column:code_title" json:"code_title" form:"code_title"` //标题

	Code_desc string `gorm:"column:code_desc" json:"code_desc" form:"code_desc"` //备注

	Code_tags string `gorm:"column:code_tags" json:"code_tags" form:"code_tags"` //标签

	Code_content string `gorm:"column:code_content" json:"code_content" form:"code_content"` //内容

	Sort int `gorm:"column:sort" json:"sort" form:"sort"` //排序

	Status int `gorm:"column:status" json:"status" form:"status"` //是否展示:1=显示,0=隐藏

	Created_at int `gorm:"autoCreateTime" form:"created_at"`

	Updated_at int `gorm:"autoUpdateTime" form:"updated_at"`

	Deleted_at gorm.DeletedAt `gorm:"deleted_at" json:"deleted_at" comment:"数据库类型必须为：datetime时间格式为2006-01-02 15:04:05"` //删除时间

}

// 删除的结构体
type CodeContentDeleteids struct {
	Ids string `form:"ids" json:"ids" comment:"删除ID" validate:"required"`
}

/*指定表名-*/
func (model *CodeContent) TableName() string {
	return "code_content"
}

/*Type类型*/

/***********时间转换************/
func (pt CodeContentParsertime) Value() (driver.Value, error) {

	pt_str := fmt.Sprintf("%v", pt)

	if pt_str == "" {
		return nil, nil
	}
	stime, _ := time.ParseInLocation("2006-01-02 15:04:05", string(pt), time.Local)

	val := stime.Unix()
	return val, nil
}

func (pt *CodeContentParsertime) Scan(v interface{}) error {
	var str int64
	switch v.(type) {
	case int64:
		str = v.(int64)
	default:
		str, _ = strconv.ParseInt(string(v.([]byte)), 10, 64)
	}
	result := time.Unix(str, 0).Format("2006-01-02 15:04:05")
	*pt = CodeContentParsertime(result)
	return nil
}

/******************类型转换**********************/

/*添加*/
func (model *CodeContent) Add_(c context.Context, param *CodeContent) (int, error) {

	err := common.DB.WithContext(c).Save(param).Error
	if err != nil {
		return 0, err
	}

	return param.Id, nil
}

/*删除*/
func (model *CodeContent) Delete_(c context.Context, delete_ids *CodeContentDeleteids) (int, error) {
	ids := strings.Split(delete_ids.Ids, ",")
	err := common.DB.WithContext(c).Where("id in (?)", ids).Delete(&CodeContent{}).Error
	if err != nil {
		return 0, err
	}
	return 1, nil
}

/*修改*/
func (model *CodeContent) Update_(c context.Context, update_data *CodeContent) (int, error) {

	err := common.DB.Model(&CodeContent{}).Where("id = ?", update_data.Id).Updates(&update_data).Error
	if err != nil {
		return 0, err
	}
	return 1, nil
}

/*查询(单条)*/
func (model *CodeContent) Detail_(c context.Context, data *CodeContent) (*CodeContent, error) {
	result := common.DB.WithContext(c)
	err := result.Where("id = ?", data.Id).First(&data).Error
	if err != nil {
		return nil, err
	}
	return data, nil
}

/*多条查询ID**/
func (model *CodeContent) FindByIds(c *gin.Context, id []string) ([]*CodeContent, error) {
	var list = make([]*CodeContent, 0)
	err := common.DB.WithContext(c).Table(model.TableName()).Where("id in (?)", id).Find(&list).Error
	if err != nil {
		return nil, err
	}
	return list, nil
}

/*查询列表*/
func (model *CodeContent) List_(c context.Context, param map[string]string) ([]CodeContent, int64, error) {
	result := common.DB.WithContext(c)
	var count int64
	var list = []CodeContent{}

	Psize, _ := strconv.Atoi(param["psize"])
	Pindex, _ := strconv.Atoi(param["pindex"])

	if Pindex <= 0 {
		Pindex = 0
	}

	Pindex = (Pindex - 1) * Psize

	Order_column, _ := param["order"]

	Order_sort, _ := param["order_sort"]
	if Order_column == "" {
		Order_column = "id"
	}
	if Order_sort == "" {
		Order_sort = "desc"
	}
	result = result.Order(Order_column + " " + Order_sort)

	err := result.Limit(Psize).Offset(Pindex).Find(&list).Limit(-1).Offset(-1).Count(&count).Error

	export_json, _ := param["export_json"]

	if export_json != "" {
		reflect_struct := CodeContent{}
		reflect_type := reflect.TypeOf(reflect_struct)
		var value_T []string
		resultarr := make(map[string]string)
		err = json.Unmarshal([]byte(export_json), &resultarr)
		if err != nil {
			fmt.Println(err.Error())
		} else {
			var title_T []string
			for i := 0; i < reflect_type.NumField(); i++ {
				nameValue := reflect_type.Field(i)
				json_key := nameValue.Tag.Get("json")
				val, ok := resultarr[json_key]
				if ok {
					title_T = append(title_T, val)
					value_T = append(value_T, nameValue.Name)
				}
				// fmt.Println(nameValue.Name)
			}
			filepath := model.ExportData(title_T, value_T, &list)
			if filepath != "" {
				/*
				*两种方式
				 */
				// c.Header("Content-Type", "application/octet-stream")
				// c.Header("Content-Disposition", "attachment; filename="+path.Base(filepath))
				// c.Header("Content-Transfer-Encoding", "binary")
				// // r, _ := os.Open(filepath)
				// r, _ := os.ReadFile(filepath)
				// c.Data(common.SUCCESS_CODE, "application/octet-stream", r)
				// c.AbortWithStatusJSON(common.SUCCESS_CODE, gin.H{
				// 	"code":    common.SUCCESS_CODE,
				// 	"message": "code",
				// 	"data":    "Request is success",
				// })

				return list, count, nil
			}
		}
	}
	if err != nil {
		return nil, count, err
	}
	return list, count, nil
}

func (model *CodeContent) ExportData(title []string, value_T []string, data *[]CodeContent) string {
	/*
	* 创建Excel
	 */
	ef := excelize.NewFile()
	sw, err := ef.NewStreamWriter("Sheet1")
	if err != nil {
		fmt.Println("创建Excel错误:", err.Error())
	}
	styleID, _ := ef.NewStyle(&excelize.Style{Font: &excelize.Font{Color: "#333333", Bold: true, Family: "微软雅黑", Size: 20}})
	row_title := make([]interface{}, 0)
	for _, v := range title {
		row_title = append(row_title, excelize.Cell{Value: v, StyleID: styleID})
	}
	err = sw.SetRow("A1", row_title)
	if err != nil {
		fmt.Println("设置Excel标题错误:", err.Error())
	}
	Dataout := make(chan []interface{}, 3)
	var swGroup sync.WaitGroup
	swGroup.Add(1)
	go func(data *[]CodeContent) {
		for _, val := range *data {
			row := make([]interface{}, 0)
			valVal := reflect.ValueOf(val)
			for _, vv := range value_T {
				valeue_val := valVal.FieldByName(vv)
				row = append(row, valeue_val)
			}
			Dataout <- row
		}
		Dataout <- []interface{}{}
		swGroup.Done()
	}(data)
	swGroup.Add(1)
	go func(sw *excelize.StreamWriter) {
		index := 2
		for data := range Dataout {
			if len(data) == 0 {
				break
			}
			cell, err := excelize.CoordinatesToCellName(1, index)
			if err != nil {
				fmt.Println("错误", err.Error())
			}
			err = sw.SetRow(cell, data, excelize.RowOpts{Height: 20})
			if err != nil {
				fmt.Println("写入数据错误", err.Error())
			}
			index++
		}
		swGroup.Done()
	}(sw)

	swGroup.Wait()
	sw.Flush()
	pathYear := time.Now().Format("200601")
	pathDay := time.Now().Format("20060102")
	filepath := "./static/upload/" + (pathYear) + "/" + (pathDay)
	_ = os.MkdirAll(filepath, os.ModePerm)
	fileName := filepath + "/" + pathDay + strconv.FormatInt(time.Now().Unix(), 10) + ".xlsx"
	err = ef.SaveAs(fileName)
	if err != nil {
		fmt.Println("保存Excel文件错误:,", err.Error())
	}
	defer func() {
		ef.Close()
		close(Dataout)
	}()
	return fileName
}
